#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <unistd.h>

#include "common/surface_utils.h"
#include "common/b_spline3.h"
#include "common/image_cache.h"

struct MapInfo{
	unsigned int rows;
	unsigned int cols;
	float tileWidth;
	float tileHeight;
	float zeroLevel;
	float scaleFactor;
	bool heightMap;
	std::string heightMapPath;
	std::string path;

	MapInfo(){
		rows  = 257;
		cols = 257;
		tileWidth = 4.0;
		tileHeight = 4.0f;
		heightMap=false;
		zeroLevel = 0.0f;
		scaleFactor = 0.22f;
	}
};

void printHelp();

int main(int argc,char** argv){
	std::string path;
	MapInfo info;

	int c;
	opterr = 0;
	while ((c = getopt (argc, argv, "c:r:p:m:z:f:w:h:ho:")) != -1){
		switch (c){
			case 'c':
				info.cols = atoi(optarg);
				break;
			case 'r':
				info.rows = atoi(optarg);
				break;
			case 'o':
				path.append(optarg);
				break;
			case 'w':
				info.tileWidth = atof(optarg);
				break;
			case 'h':
				info.tileHeight = atof(optarg);
				break;
			case 'z':
				info.zeroLevel = atof(optarg);
				break;
			case 'f':
				info.scaleFactor = atof(optarg);
				break;
			case 'm':
				info.heightMap = true;
				info.heightMapPath.append(optarg);
				break;
			case 'p':
				info.path.append(optarg);
				break;
			default:
				printHelp();
				return 0;
		}
	}

	if(path==""){
		printHelp();
		return 0;
	}

	Surface map;

	if(info.heightMap){
		ImageCache::TexturePtr ptr = ImageCache::instance().load(info.path,info.heightMapPath);
		SurfaceUtils::instance().calculateTiledSurfaceHeightMap(Point(0,0,1),Point(0,0,0),info.rows,info.cols,info.tileWidth,info.tileHeight,*ptr,info.scaleFactor,info.zeroLevel,map);
		SurfaceUtils::instance().calculateTiledSurfaceHeightMapIndices(info.rows,info.cols,map);
		SurfaceUtils::instance().calculateTiledSurfaceHeightMapNormals(map);
	}else{
		SurfaceUtils::instance().calculateTiledSurface(Point(0,0,1),Point(0,0,0),info.rows,info.cols,info.tileWidth,info.tileHeight,map);
		SurfaceUtils::instance().calculateTiledSurfaceIndices(info.rows,info.cols,map);
	}
	std::ofstream out((path+".obj").c_str());
	SurfaceUtils::instance().surfaceToObj(map,out,path+".mtl");
	return 0;
}

void printHelp(){
	std::cout << "Modo de uso: " << std::endl;
	std::cout << "./mapGenerator [-rcwh] [-m heightmap.png -zf] -o output_file" << std::endl;
	std::cout << "Opciones:" << std::endl;
	std::cout << "\t -o : Obj de salida" << std::endl;
	std::cout << "\t -r : Numero de filas" << std::endl;
	std::cout << "\t -c : Numero de columnas" << std::endl;
	std::cout << "\t -w : Ancho tile" << std::endl;
	std::cout << "\t -h : Alto tile" << std::endl;
	std::cout << "\t -m : Archivo a utilizar como height map" << std::endl;
	std::cout << "\t -p : Height map path" << std::endl;
	std::cout << "\t -z : Nivel de referencia cero en el height map" << std::endl;
	std::cout << "\t -f : Factor de escala del height map" << std::endl;
}
